﻿/// <summary>
/// FileName: BinaryExpression.cs
/// Author: Jiang Xiaolong
/// Created Time: 2015.05.12
/// Version: 1.0
/// Company: Sunnytech
/// Function: 二元表达式；
///
/// Changed By:
/// Modification Time:
/// Discription:
/// </summary>
using System;
using System.Collections.Generic;
using Expression.api;

namespace Expression.impl
{
	public class BinaryExpression : ExpressionTree
	{
		public Type ExpType { get; set; }

		public enum BinaryOperator { Add, Subtract, Multiply, Divide, Modulo, Power, LT, LT_EQ, EQ, GT_EQ, GT, NEQ, And, Or, Not }

		private static Dictionary<string, BinaryOperator> _opDic = new Dictionary<string, BinaryOperator>();

		private BinaryOperator _op;

		private static Dictionary<BinaryOperator, int> _priority = new Dictionary<BinaryOperator, int>();

		private ExpressionTree _left { get; set; }

		private ExpressionTree _right { get; set; }

		private bool _isSealed = false;

		static BinaryExpression()
		{
			_opDic.Add("+", BinaryOperator.Add);
			_opDic.Add("-", BinaryOperator.Subtract);
			_opDic.Add("*", BinaryOperator.Multiply);
			_opDic.Add("/", BinaryOperator.Divide);
			_opDic.Add("%", BinaryOperator.Modulo);
			_opDic.Add("**", BinaryOperator.Power);
			_opDic.Add("^", BinaryOperator.Power);
			_opDic.Add("<", BinaryOperator.LT);
			_opDic.Add("<=", BinaryOperator.LT_EQ);
			_opDic.Add("==", BinaryOperator.EQ);
			_opDic.Add(">=", BinaryOperator.GT_EQ);
			_opDic.Add(">", BinaryOperator.GT);
			_opDic.Add("!=", BinaryOperator.NEQ);
			_opDic.Add("&&", BinaryOperator.And);
			_opDic.Add("||", BinaryOperator.Or);
			_opDic.Add("!", BinaryOperator.Not);
			_opDic.Add("！", BinaryOperator.Not);

			_priority.Add(BinaryOperator.Not, 2);
			_priority.Add(BinaryOperator.Power, 3);
			_priority.Add(BinaryOperator.Multiply, 4); _priority.Add(BinaryOperator.Divide, 4); _priority.Add(BinaryOperator.Modulo, 4);
			_priority.Add(BinaryOperator.Add, 5); _priority.Add(BinaryOperator.Subtract, 5);
			_priority.Add(BinaryOperator.LT, 6); _priority.Add(BinaryOperator.LT_EQ, 6); _priority.Add(BinaryOperator.EQ, 6); _priority.Add(BinaryOperator.GT_EQ, 6); _priority.Add(BinaryOperator.GT, 6); _priority.Add(BinaryOperator.NEQ, 6);
			_priority.Add(BinaryOperator.And, 7); _priority.Add(BinaryOperator.Or, 7);

		}

		public BinaryExpression(ExpressionTree left_exp, ExpressionTree right_exp, BinaryOperator op)
		{
			this._left = left_exp;
			this._right = right_exp;
			this._op = op;
			this.ExpType = ResultAutoType(left_exp, right_exp, op);
            //UnityEngine.Debug.Log(ExpType.ToString());
            //UnityEngine.Debug.LogWarning(_left.ToString());
            //UnityEngine.Debug.LogWarning(_right.ToString());
            //UnityEngine.Debug.LogWarning(_left.ExpType.ToString());
            //UnityEngine.Debug.LogWarning(_right.ExpType.ToString());
		}

		public BinaryExpression(ExpressionTree left_exp, ExpressionTree right_exp, string op)
		{
			this._left = left_exp;
			this._right = right_exp;
			this._op = _opDic[op];
			this.ExpType = ResultAutoType(left_exp, right_exp, this._op);
		}

		private Type ResultAutoType(ExpressionTree left, ExpressionTree right, BinaryOperator op)
		{
			if (op == BinaryOperator.Add)
			{
				if (left.ExpType == typeof(string) || right.ExpType == typeof(string))
				{
					return typeof(string);
				}
				else if (left.ExpType == typeof(bool) || left.ExpType == typeof(bool))
				{
					return null;
				}
				else if (left.ExpType == typeof(double) || right.ExpType == typeof(double))
				{
					return typeof(double);
				}
                else if (left.ExpType == typeof(float) || right.ExpType == typeof(float) || left.ExpType == typeof(System.Single) || right.ExpType == typeof(System.Single))
				{
					return typeof(float);
				}
				else
				{
                    return typeof(int);
				}
			}
			else if (op == BinaryOperator.Divide || op == BinaryOperator.Multiply || op == BinaryOperator.Modulo || op == BinaryOperator.Power || op == BinaryOperator.Subtract)
			{
				if (left.ExpType == typeof(string) || right.ExpType == typeof(string) || left.ExpType == typeof(bool) || left.ExpType == typeof(bool))
				{
					return null;
				}
				else if (left.ExpType == typeof(double) || right.ExpType == typeof(double))
				{
					return typeof(double);
				}
                else if (left.ExpType == typeof(float) || right.ExpType == typeof(float) || left.ExpType == typeof(System.Single) || right.ExpType == typeof(System.Single))
				{
					return typeof(float);
				}
				else
				{
					return typeof(int);
				}
			}
			else if (op == BinaryOperator.LT || op == BinaryOperator.LT_EQ || op == BinaryOperator.GT_EQ || op == BinaryOperator.GT)
			{
				if (left.ExpType == typeof(string) || right.ExpType == typeof(string) || left.ExpType == typeof(bool) || left.ExpType == typeof(bool))
				{
					return null;
				}
				else
				{
					return typeof(bool);
				}
			}
			else if (op == BinaryOperator.NEQ || op == BinaryOperator.EQ)
			{
				if (left.ExpType != right.ExpType)
				{
					return null;
				}
				else
				{
					return typeof(bool);
				}
			}
			else
			{
				return typeof(bool);
			}
		}

		public object Evaluate()
		{
			if (ExpType == null)
			{
				return null;
			}
            if (_left.GetType() == typeof(FunctionExpression))
            {
                _left.Evaluate();
            }
            if (_right.GetType() == typeof(FunctionExpression))
            {
                _right.Evaluate();
            }

            ExpType = ResultAutoType(_left, _right, _op);
			object leftValue = _left.Evaluate();
			object rightValue = _right.Evaluate();

			if (leftValue == null || rightValue == null)
			{
				return null;
			}
			if (_op == BinaryOperator.Add)
			{
				if (ExpType == typeof(string))
					return leftValue.ToString() + rightValue.ToString();
				else if (ExpType == typeof(double))
					return double.Parse(leftValue.ToString()) + double.Parse(rightValue.ToString());
				else if (ExpType == typeof(float))
					return float.Parse(leftValue.ToString()) + float.Parse(rightValue.ToString());
                else if (ExpType == typeof(System.Single))
                    return float.Parse(leftValue.ToString()) + float.Parse(rightValue.ToString());
				else
					return int.Parse(leftValue.ToString()) + int.Parse(rightValue.ToString());
			}
			else if (_op == BinaryOperator.Subtract)
			{
				if (ExpType == typeof(double))
					return double.Parse(leftValue.ToString()) - double.Parse(rightValue.ToString());
				else if (ExpType == typeof(float))
					return float.Parse(leftValue.ToString()) - float.Parse(rightValue.ToString());
                else if (ExpType == typeof(System.Single))
                    return float.Parse(leftValue.ToString()) - float.Parse(rightValue.ToString());
				else
					return int.Parse(leftValue.ToString()) - int.Parse(rightValue.ToString());
			}
			else if (_op == BinaryOperator.Multiply)
			{
				if (ExpType == typeof(double))
					return double.Parse(leftValue.ToString()) * double.Parse(rightValue.ToString());
				else if (ExpType == typeof(float))
					return float.Parse(leftValue.ToString()) * float.Parse(rightValue.ToString());
                else if (ExpType == typeof(System.Single))
                    return float.Parse(leftValue.ToString()) * float.Parse(rightValue.ToString());
				else
					return int.Parse(leftValue.ToString()) * int.Parse(rightValue.ToString());
			}
			else if (_op == BinaryOperator.Divide)
			{
				if (ExpType == typeof(double))
					return double.Parse(leftValue.ToString()) / double.Parse(rightValue.ToString());
				else if (ExpType == typeof(float))
					return float.Parse(leftValue.ToString()) / float.Parse(rightValue.ToString());
                else if (ExpType == typeof(System.Single))
                    return float.Parse(leftValue.ToString()) / float.Parse(rightValue.ToString());
				else
					return int.Parse(leftValue.ToString()) / int.Parse(rightValue.ToString());
			}
			else if (_op == BinaryOperator.Modulo)
			{
				if (ExpType == typeof(double))
					return double.Parse(leftValue.ToString()) % double.Parse(rightValue.ToString());
				else if (ExpType == typeof(float))
					return float.Parse(leftValue.ToString()) % float.Parse(rightValue.ToString());
                else if (ExpType == typeof(System.Single))
                    return float.Parse(leftValue.ToString()) % float.Parse(rightValue.ToString());
				else
					return int.Parse(leftValue.ToString()) % int.Parse(rightValue.ToString());
			}
			else if (_op == BinaryOperator.Power)
			{
				if (ExpType == typeof(double))
					return Math.Pow(double.Parse(leftValue.ToString()), double.Parse(rightValue.ToString()));
				else if (ExpType == typeof(float))
					return (float)Math.Pow(double.Parse(leftValue.ToString()), double.Parse(rightValue.ToString()));
                else if (ExpType == typeof(System.Single))
                    return (float)Math.Pow(double.Parse(leftValue.ToString()), double.Parse(rightValue.ToString()));
				else
					return (int)Math.Pow(double.Parse(leftValue.ToString()), double.Parse(rightValue.ToString()));
			}
			else if (_op == BinaryOperator.And)
			{
				bool a = GetBoolen(leftValue);
				bool b = GetBoolen(rightValue);
				return a && b;
			}
			else if (_op == BinaryOperator.Or)
			{
				bool a = GetBoolen(leftValue);
				bool b = GetBoolen(rightValue);
				return a || b;
			}
			else if (_op == BinaryOperator.LT)
			{
				return double.Parse(leftValue.ToString()) < double.Parse(rightValue.ToString());
			}
			else if (_op == BinaryOperator.LT_EQ)
			{
				return double.Parse(leftValue.ToString()) <= double.Parse(rightValue.ToString());
			}
			else if (_op == BinaryOperator.GT_EQ)
			{
				return double.Parse(leftValue.ToString()) >= double.Parse(rightValue.ToString());
			}
			else if (_op == BinaryOperator.GT)
			{
				return double.Parse(leftValue.ToString()) > double.Parse(rightValue.ToString());
			}
			else if (_op == BinaryOperator.EQ)
			{
				return leftValue.Equals(rightValue);
			}
			else if (_op == BinaryOperator.NEQ)
			{
				return !leftValue.Equals(rightValue);
			}
			else
			{
				bool a = GetBoolen(leftValue);
				return !a;
			}
		}

		private bool GetBoolen(object value)
		{
			if (value.GetType() == typeof(double))
			{
				if (double.Parse(value.ToString()) == 0)
					return false;
				else
					return true;
			}
            else if (value.GetType() == typeof(float) || value.GetType() == typeof(System.Single))
			{
				if (float.Parse(value.ToString()) == 0)
					return false;
				else
					return true;
			}
			else if (value.GetType() == typeof(int))
			{
				if (int.Parse(value.ToString()) == 0)
					return false;
				else
					return true;
			}
			else if (value.GetType() == typeof(string))
			{
				if (value.ToString() == "")
				{
					return false;
				}
				else
				{
					return true;
				}
			}
			else
			{
				return bool.Parse(value.ToString());
			}
		}

		public void SetLeftExp(ExpressionTree left_exp)
		{
			this._left = left_exp;
		}

		public void SetRightExp(ExpressionTree right_exp)
		{
			this._right = right_exp;
		}

		public BinaryOperator GetOp()
		{
			return _op;
		}

		public ExpressionTree GetLeftExp()
		{
			return _left;
		}

		public ExpressionTree GetRightExp()
		{
			return _right;
		}

		public bool IsOperatorValid(string op)
		{
			if (_opDic.ContainsKey(op))
			{
				return true;
			}
			else
			{
				return false;
			}
		}

		public bool IsSealed()
		{
			return _isSealed;
		}

		public void SetSeal()
		{
			_isSealed = true;
		}

		public int GetPriority()
		{
			return _priority[_op];
		}

		public int GetPriority(BinaryOperator op)
		{
			return _priority[op];
		}

		public override string ToString()
		{
			return "( " + _left.ToString() + " " + _op.ToString() + " " + _right.ToString() + " )";
		}

        public ExpressionTree Clone ()
        {
            BinaryExpression expClone = new BinaryExpression(_left.Clone(), _right.Clone(), _op);
            return expClone;
        }
	}

}

